#include <fmt/core.h>
#include <fstream>
#include <string>

#include "options.h"
#include "local_store.h"

#pragma once

namespace kawauso {

    /**
     * TODO description
     */
    enum class LogLevel {
        INFO, WARN, ERROR
    };

    /**
     * TODO description
     */
    class Logger {
        LoggerOptions options;
        std::mutex    fileMutex;
        FILE *        fileStream = nullptr;
        uint32_t      fileId = 0;
        uint32_t      fileSize = 0;
    public:
        explicit Logger(const LoggerOptions &options);
        ~Logger();

        /**
         * Output log message at specified level.
         * @param level output level
         * @param message message for output
         */
        void output(LogLevel level, const std::string &message);

    private:
        void openNewLogFile();
        bool closeLogFile();
    public:
        static Logger global;
    };

    /**
     * Format and output log message at info level
     * @param fmt template for formatting message
     * @param args arguments for formatting message
     */
    template<typename... Args>
    inline void info(fmt::format_string<Args...> fmt, Args &&...args) {
        Logger::global.output(LogLevel::INFO, format(fmt, std::forward<Args>(args)...));
    }

    /**
     * Format and output log message at warn level
     * @param fmt template for formatting message
     * @param args arguments for formatting message
     */
    template<typename... Args>
    inline void warn(fmt::format_string<Args...> fmt, Args &&...args) {
        Logger::global.output(LogLevel::WARN, format(fmt, std::forward<Args>(args)...));
    }

    /**
     * Format and output log message at error level
     * @param fmt template for formatting message
     * @param args arguments for formatting message
     */
    template<typename... Args>
    inline void error(fmt::format_string<Args...> fmt, Args &&...args) {
        Logger::global.output(LogLevel::ERROR, format(fmt, std::forward<Args>(args)...));
    }

}